/**
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 2006 Samsung Electronics, co. ltd  All rights reserved.
 
Module Name:  
 
    SC2443PDD.CPP	
 
Abstract:
 
    S3C2443 USB2.0 function device driver 
 
rev:
 
    2006.9.4	: First release (Woosuk Chung)
 
**/
//	Programer: Visual.Wei
//	Date: 2007-5-17

#include <windows.h>
#include <nkintr.h>
#include <oal.h>
#include <S3C2443.h>
#include "sc2443pdd.h"

#define UDC_REG_PRIORITY_VAL _T("Priority256")
#define DBG 0

enum EP0_STATE {
    EP0_STATE_IDLE = 0,
    EP0_STATE_IN_DATA_PHASE,
    EP0_STATE_OUT_DATA_PHASE
};

#define IN_TRANSFER  1
#define OUT_TRANSFER 2

typedef struct EP_STATUS
{
	DWORD                   dwEndpointNumber;
	DWORD                   dwDirectionAssigned;
	DWORD                   dwPacketSizeAssigned;
	BOOL                    fInitialized;
	DWORD                   dwEndpointType;
	PSTransfer              pTransfer;
	CRITICAL_SECTION        cs;
}
*PEP_STATUS;

#define LOCK_ENDPOINT(peps)
#define UNLOCK_ENDPOINT(peps)


#define EP_0_PACKET_SIZE    0x40    // usb2.0

#define ENDPOINT_COUNT  9
#define EP_VALID(x)     ((x) < ENDPOINT_COUNT)


#define DEFAULT_PRIORITY 100

//kim sang hee

DWORD StallFlag= FALSE;

typedef struct CTRL_PDD_CONTEXT
{
	PVOID             pvMddContext;
	DWORD             dwSig;
	HANDLE            hIST;
	HANDLE            hevInterrupt;
	BOOL              fRunning;
	CRITICAL_SECTION  csIndexedRegisterAccess;
	BOOL              fSpeedReported;
	BOOL              fRestartIST;
	BOOL              fExitIST;
	BOOL              attachedState;
	BOOL              sendDataEnd;
	EP0_STATE         Ep0State;

	// registry
	DWORD             dwIOBase;
	DWORD             dwSysIntr;
	DWORD             dwIrq;
	DWORD             dwIOLen;
	DWORD             dwISTPriority;

	USB_DEVICE_REQUEST udr;
	EP_STATUS         rgEpStatus[ENDPOINT_COUNT];

	PFN_UFN_MDD_NOTIFY      pfnNotify;
	HANDLE                  hBusAccess;
	CEDEVICE_POWER_STATE    cpsCurrent;
}
*PCTRLR_PDD_CONTEXT;

static struct CTRL_PDD_CONTEXT g_pdd;

#define SC2443_SIG '2443' // "SC2443" signature

#define IS_VALID_SC2443_CONTEXT(ptr) \
    ( (ptr != NULL) && (ptr->dwSig == SC2443_SIG) )


#ifdef DEBUG

#define ZONE_POWER           DEBUGZONE(8)

UFN_GENERATE_DPCURSETTINGS(UFN_DEFAULT_DPCURSETTINGS_NAME,
                           _T("Power"), _T(""), _T(""), _T(""),
                           DBG_ERROR | DBG_INIT);
// Caution: Turning on more debug zones can cause STALLs due
// to corrupted setup packets.

// Validate the context.
static
VOID
ValidateContext(
    PCTRLR_PDD_CONTEXT pContext
)
{
	PREFAST_DEBUGCHK(pContext);
	DEBUGCHK(pContext->dwSig == SC2443_SIG);
	DEBUGCHK(!pContext->hevInterrupt || pContext->hIST);
	DEBUGCHK(VALID_DX(pContext->cpsCurrent));
	DEBUGCHK(pContext->pfnNotify);
}

#else
#define ValidateContext(ptr)
#endif

volatile BYTE *g_pUDCBase;

static BYTE USBClassInfo;
#define USB_RNDIS  0
#define USB_Serial 1
#define USB_MSF    2

#define SET   TRUE
#define CLEAR FALSE

#define CTRLR_BASE_REG_ADDR(offset) ((volatile ULONG*) ( (g_pUDCBase) + (offset)))

#define DRIVER_USB_KEY TEXT("Drivers\\USB\\FunctionDrivers")
#define DRIVER_USB_VALUE TEXT("DefaultClientDriver")

// Read a register.
inline
WORD
ReadReg(
    PCTRLR_PDD_CONTEXT pContext,
    DWORD dwOffset
)
{
	DEBUGCHK(IS_VALID_SC2443_CONTEXT(pContext));

	volatile ULONG *pbReg = CTRLR_BASE_REG_ADDR(dwOffset);
	WORD bValue = (WORD) *pbReg;
	return bValue;
}


// Write a register.
inline
VOID
WriteReg(
    PCTRLR_PDD_CONTEXT pContext,
    DWORD dwOffset,
    DWORD bValue
)
{
	DEBUGCHK(IS_VALID_SC2443_CONTEXT(pContext));

	volatile ULONG *pbReg = CTRLR_BASE_REG_ADDR(dwOffset);
	*pbReg = (ULONG) bValue;
}



// Calling with dwMask = 0 and SET reads and writes the contents unchanged.
inline
BYTE
SetClearReg(
    PCTRLR_PDD_CONTEXT pContext,
    DWORD dwOffset,
    WORD dwMask,
    BOOL  bSet
)
{
	DEBUGCHK(IS_VALID_SC2443_CONTEXT(pContext));

	volatile ULONG *pbReg = CTRLR_BASE_REG_ADDR(dwOffset);
	BYTE bValue = (BYTE) *pbReg;

	if (bSet)
	{
		bValue |= dwMask;
	}
	else
	{
		bValue &= ~dwMask;
	}

	*pbReg = bValue;

	return bValue;
}
// Calling with dwMask = 0 and SET reads and writes the contents unchanged.
inline
BYTE
SetClearIndexedReg(
    PCTRLR_PDD_CONTEXT pContext,
    DWORD dwEndpoint,
    DWORD dwOffset,
    WORD dwMask,
    BOOL  bSet
)
{
	DEBUGCHK(IS_VALID_SC2443_CONTEXT(pContext));
	BYTE bValue = 0;

	// Write the EP number to the index reg
	WriteReg(pContext, IR, (BYTE) dwEndpoint);
	// Now Write the Register associated with this Endpoint for a given offset
	bValue = SetClearReg(pContext, dwOffset, dwMask, bSet);

	return bValue;
}

// Read an indexed register.
inline
WORD
ReadIndexedReg(
    PCTRLR_PDD_CONTEXT pContext,
    DWORD dwEndpoint,
    DWORD regOffset
)
{
	DEBUGCHK(IS_VALID_SC2443_CONTEXT(pContext));

	// Write the EP number to the index reg
	WriteReg(pContext, IR, (BYTE) dwEndpoint);
	// Now Read the Register associated with this Endpoint for a given offset
	WORD bValue = ReadReg(pContext, regOffset);
	return bValue;
}


// Write an indexed register.
inline
VOID
WriteIndexedReg(
    PCTRLR_PDD_CONTEXT pContext,
    DWORD dwEndpoint,
    DWORD regOffset,
    DWORD  bValue
)
{
	DEBUGCHK(IS_VALID_SC2443_CONTEXT(pContext));

	// Write the EP number to the index reg
	WriteReg(pContext, IR, (BYTE) dwEndpoint);
	// Now Write the Register associated with this Endpoint for a given offset
	WriteReg(pContext, regOffset, bValue);
}

/*++
 
Routine Description:
 
Return the data register of an endpoint.
 
Arguments:
 
dwEndpoint - the target endpoint
 
Return Value:
 
The data register of the target endpoint.
 
--*/
static
volatile ULONG*
_GetDataRegister(
    DWORD        dwEndpoint
)
{
	volatile ULONG *pulDataReg = NULL;

	//
	// find the data register (non-uniform offset)
	//
	switch (dwEndpoint)
	{
	case  0:
		pulDataReg = CTRLR_BASE_REG_ADDR(EP0BR);
		break;
	case  1:
		pulDataReg = CTRLR_BASE_REG_ADDR(EP1BR);
		break;
	case  2:
		pulDataReg = CTRLR_BASE_REG_ADDR(EP2BR);
		break;
	case  3:
		pulDataReg = CTRLR_BASE_REG_ADDR(EP3BR);
		break;
	case  4:
		pulDataReg = CTRLR_BASE_REG_ADDR(EP4BR);
		break;
	case  5:
		pulDataReg = CTRLR_BASE_REG_ADDR(EP5BR);
		break;
	case  6:
		pulDataReg = CTRLR_BASE_REG_ADDR(EP6BR);
		break;
	case  7:
		pulDataReg = CTRLR_BASE_REG_ADDR(EP7BR);
		break;
	case  8:
		pulDataReg = CTRLR_BASE_REG_ADDR(EP8BR);
		break;
	default:
		DEBUGCHK(FALSE);
		break;
	}

	return pulDataReg;
} // _GetDataRegister


// Retrieve the endpoint status structure.
inline
static
PEP_STATUS
GetEpStatus(
    PCTRLR_PDD_CONTEXT pContext,
    DWORD dwEndpoint
)
{
	ValidateContext(pContext);
	DEBUGCHK(EP_VALID(dwEndpoint));

	PEP_STATUS peps = &pContext->rgEpStatus[dwEndpoint];

	return peps;
}


// Return the irq bit for this endpoint.
inline
static
BYTE
EpToIrqStatBit(
    DWORD dwEndpoint
)
{
	DEBUGCHK(EP_VALID(dwEndpoint));

	return (1 << (BYTE)dwEndpoint);
}

/*++
 
Routine Description:
 
Enable the interrupt of an endpoint.
 
Arguments:
 
dwEndpoint - the target endpoint
 
Return Value:
 
None.
 
--*/
static
VOID
EnableDisableEndpointInterrupt(
    PCTRLR_PDD_CONTEXT  pContext,
    DWORD               dwEndpoint,
    BOOL                fEnable
)
{
	// Disable the Endpoint Interrupt
	WORD bEpIntReg = ReadReg(pContext, EIER);
	BYTE bIrqEnBit = EpToIrqStatBit(dwEndpoint);

	if (fEnable)
	{
		bEpIntReg |= bIrqEnBit;
	}
	else
	{
		bEpIntReg &= ~bIrqEnBit;
	}

	WriteReg(pContext, EIER, bEpIntReg);

}

static
inline
VOID
EnableEndpointInterrupt(
    PCTRLR_PDD_CONTEXT  pContext,
    DWORD               dwEndpoint
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	EnableDisableEndpointInterrupt(pContext, dwEndpoint, TRUE);

	FUNCTION_LEAVE_MSG();
}

static
inline
VOID
DisableEndpointInterrupt(
    PCTRLR_PDD_CONTEXT  pContext,
    DWORD               dwEndpoint
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	EnableDisableEndpointInterrupt(pContext, dwEndpoint, FALSE);

	FUNCTION_LEAVE_MSG();
}

/*++
 
Routine Description:
 
Clear the interrupt status register index of an endpoint.
 
Arguments:
 
dwEndpoint - the target endpoint
 
Return Value:
 
None.
 
--*/
static
VOID
ClearEndpointInterrupt(
    PCTRLR_PDD_CONTEXT pContext,
    DWORD        dwEndpoint
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	// Clear the Endpoint Interrupt
	BYTE bIntBit = EpToIrqStatBit(dwEndpoint);
	WriteReg(pContext, EIR, bIntBit);

	FUNCTION_LEAVE_MSG();
} // _ClearInterrupt


// Reset an endpoint

VOID
ResetEndpoint(
    PCTRLR_PDD_CONTEXT pContext,
    EP_STATUS *peps
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	ValidateContext(pContext);
	PREFAST_DEBUGCHK(peps);

	RETAILMSG(DBG, (_T(" ResetEndpoint \r\n")));

	// Since Reset can be called before/after an Endpoint has been configured,
	// it is best to clear all IN and OUT bits associated with endpoint.
	DWORD dwEndpoint = peps->dwEndpointNumber;
	//0816
	WORD bEDR;
	if(dwEndpoint == 0 )
	{
		// Clear all EP0 Status bits
		WriteReg(pContext, EP0SR, (EP0SHT | EP0TST |EP0RSR));
		WriteReg(pContext, EP0CR, 0x0000);
	}
	else if(dwEndpoint < ENDPOINT_COUNT)
	{
		// Clear all EP Status bits
		WriteIndexedReg(pContext, dwEndpoint, ESR, (OSD | DTCZ | SPT | FFS | FSC | TPS));
		// Clear all EP Control bits
		bEDR = ReadIndexedReg(pContext, dwEndpoint, EDR);
		if(bEDR & (0x1 << dwEndpoint))
		{		// Tx
			WriteIndexedReg(pContext, dwEndpoint, ECR, 0x0000);  // Single Buffer Mode
		}
		else
		{
			WriteIndexedReg(pContext, dwEndpoint, ECR, 0x0080); // Dual Buffer Mode
		}


		// Clear and disable endpoint interrupt
		WriteReg(pContext, EIR, EpToIrqStatBit(peps->dwEndpointNumber));
		DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
	}
	else
	{
		DEBUGCHK(FALSE);
	}

	FUNCTION_LEAVE_MSG();
}



// Reset the device and EP0.

VOID
ResetDevice(
    PCTRLR_PDD_CONTEXT pContext
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	DEBUGCHK(IS_VALID_SC2443_CONTEXT(pContext));

	RETAILMSG(DBG, (_T(" ResetDevice \r\n")));

	// Reset System Control Register
	WriteReg(pContext, SCR, 0x0020);

	// Reset System Status Register
	WriteReg(pContext, SSR, (VBUSOFF | VBUSON | TBM | SDE | HFRM | HFSUSP | HFRES ) );


	// Disable endpoint interrupts - write Zeros to Disable
	WriteReg(pContext, EIER, EP_INTERRUPT_DISABLE_ALL);

	// End point Interrupt Status - Write a '1' to Clear
	WriteReg(pContext, EIR, CLEAR_ALL_EP_INTRS);

	// Reset all endpoints
	for (DWORD dwEpIdx = 0; dwEpIdx < ENDPOINT_COUNT; ++dwEpIdx)
	{
		EP_STATUS *peps = GetEpStatus(pContext, dwEpIdx);
		ResetEndpoint(pContext, peps);
	}

	FUNCTION_LEAVE_MSG();
}


static
VOID
CompleteTransfer(
    PCTRLR_PDD_CONTEXT pContext,
    PEP_STATUS peps,
    DWORD dwUsbError
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	PSTransfer pTransfer = peps->pTransfer;
	peps->pTransfer = NULL;

	pTransfer->dwUsbError = dwUsbError;
	pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_TRANSFER_COMPLETE,
	                    (DWORD) pTransfer);

	FUNCTION_LEAVE_MSG();
}


#ifdef DEBUG
static
VOID
ValidateTransferDirection(
    PCTRLR_PDD_CONTEXT pContext,
    PEP_STATUS peps,
    PSTransfer pTransfer
)
{
	DEBUGCHK(pContext);
	PREFAST_DEBUGCHK(peps);
	PREFAST_DEBUGCHK(pTransfer);

	if (peps->dwEndpointNumber != 0)
	{
		DEBUGCHK(peps->dwDirectionAssigned == pTransfer->dwFlags);
	}
}
#else
#define ValidateTransferDirection(ptr1, ptr2, ptr3)
#endif


// Read data from an endpoint.

static
VOID
HandleRx(
    PCTRLR_PDD_CONTEXT       pContext,
    PEP_STATUS peps,
    PBOOL pfCompleted,
    PDWORD pdwStatus
)
{

	BOOL fCompleted = FALSE;
	DWORD dwStatus = ERROR_GEN_FAILURE;
	DWORD dwEndpoint = peps->dwEndpointNumber;
	BYTE bRet = 0;
	WORD bEpIrqStat;

	SETFNAME();
	FUNCTION_ENTER_MSG();

	bEpIrqStat = ReadIndexedReg(pContext, dwEndpoint, ESR);

	PSTransfer pTransfer = peps->pTransfer;

	pTransfer = peps->pTransfer;
	if (pTransfer)
	{
		DEBUGCHK(pTransfer->dwFlags == USB_OUT_TRANSFER);
		DEBUGCHK(pTransfer->dwUsbError == UFN_NOT_COMPLETE_ERROR);

		ValidateTransferDirection(pContext, peps, pTransfer);

		DEBUGCHK(peps->fInitialized);


		{
			volatile ULONG *pulFifoReg = _GetDataRegister(dwEndpoint);
			DEBUGCHK(pulFifoReg != NULL);

			PBYTE  pbBuffer =  (PBYTE)pTransfer->pvBuffer + pTransfer->cbTransferred;

			DWORD cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;
			DWORD cbFifoWord = ReadIndexedReg(pContext, dwEndpoint, BRCR);

			WORD ReadData = 0 ;
			DWORD cbFifo;

			if(dwEndpoint ==0)
			{
				if (bEpIrqStat & EP0LWO)
					cbFifo = cbFifoWord*2-1;
				else
					cbFifo = cbFifoWord*2;
			}
			else
			{
				if (bEpIrqStat & LWO)
					cbFifo = cbFifoWord*2-1;
				else
					cbFifo = cbFifoWord*2;
			}

			DEBUGCHK(cbFifo <= peps->dwPacketSizeAssigned);

			// Read from the FIFO
			const DWORD cbRead = min(cbFifo, cbBuffer);
			DWORD cbToRead;
			for (cbToRead = 0; cbToRead < cbRead; cbToRead+=2)
			{
				ReadData= (WORD)*pulFifoReg;
				*pbBuffer = (BYTE)ReadData;
				*(pbBuffer+1) = (BYTE)(ReadData>>8);
				pbBuffer +=2;
			}

			pTransfer->cbTransferred += cbRead;

			if ( (cbRead < peps->dwPacketSizeAssigned) ||
			        (pTransfer->cbTransferred == pTransfer->cbBuffer) )
			{
				// Short packet or filled buffer. Complete transfer.
				fCompleted = TRUE;
				dwStatus = UFN_NO_ERROR;
			}

			if (dwEndpoint == 0)
			{
				SetClearReg(pContext, EP0SR, EP0RSR, SET); //add by shkim for RNDIS
				if (fCompleted)
				{
					pContext->Ep0State = EP0_STATE_IDLE;
				}
			}
			else
			{
				if((peps->dwEndpointType == USB_ENDPOINT_TYPE_BULK) && (!fCompleted))
				{
					if(bEpIrqStat & PSIF)
					{
						pbBuffer =  (PBYTE)pTransfer->pvBuffer + pTransfer->cbTransferred;
						cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;
						cbFifoWord = ReadIndexedReg(pContext, dwEndpoint, BRCR);
						ReadData = 0 ;

						if (bEpIrqStat & LWO)
							cbFifo = cbFifoWord*2-1;
						else
							cbFifo = cbFifoWord*2;

						// Read from the FIFO
						const DWORD cbRead = min(cbFifo, cbBuffer);
						for (cbToRead = 0; cbToRead < cbRead; cbToRead+=2)
						{
							ReadData= (WORD)*pulFifoReg;
							*pbBuffer = (BYTE)ReadData;
							*(pbBuffer+1) = (BYTE)(ReadData>>8);
							pbBuffer +=2;
						}

						pTransfer->cbTransferred += cbRead;

						if ( (cbRead < peps->dwPacketSizeAssigned) ||
						        (pTransfer->cbTransferred == pTransfer->cbBuffer) )
						{
							// Short packet or filled buffer. Complete transfer.
							fCompleted = TRUE;
							dwStatus = UFN_NO_ERROR;
						}
						//RETAILMSG(1, (_T("Two Packet, bEpIrqStat : 0x%08x \r\n"),bEpIrqStat));
					}
					else
					{
						//RETAILMSG(1, (_T("before_NO One Packet, bEpIrqStat : 0x%08x \r\n"),bEpIrqStat));
						//bEpIrqStat = ReadIndexedReg(pContext, dwEndpoint, ESR);
						RETAILMSG(DBG, (_T("Now_NO One Packet, bEpIrqStat : 0x%08x \r\n"),bEpIrqStat));
					}

				}

			}
		}



		if (fCompleted)
		{
			RETAILMSG(DBG, (_T("%s RxDone Ep%x BufferSize=%u, Xfrd=%u\r\n"),
			                pszFname, dwEndpoint,pTransfer->cbBuffer, pTransfer->cbTransferred));
		}
	}
	else //by kim
		SetClearIndexedReg(pContext,dwEndpoint,ESR,RPS,SET);


	*pfCompleted = fCompleted;
	*pdwStatus = dwStatus;
	FUNCTION_LEAVE_MSG();
}


// Write data to an endpoint.
static
VOID
HandleTx(
    PCTRLR_PDD_CONTEXT       pContext,
    PEP_STATUS peps,
    BOOL fEnableInterrupts
)
{
	SETFNAME();
	DEBUGCHK(pContext);
	PREFAST_DEBUGCHK(peps);

	// This routine can be entered from both ISTMain and MDD/Client threads so
	// need critical section.

	FUNCTION_ENTER_MSG();

	// BYTE bRet = 0;
#if 1

	BOOL fCompleted = FALSE;
	PSTransfer pTransfer = peps->pTransfer;
	DWORD dwStatus = ERROR_GEN_FAILURE;
	DEBUGCHK(peps->fInitialized);
	DWORD dwEndpoint = peps->dwEndpointNumber;

	pTransfer = peps->pTransfer;

	if (pTransfer)
	{
		ValidateTransferDirection(pContext, peps, pTransfer);

		DEBUGCHK(pTransfer->dwFlags == USB_IN_TRANSFER);
		DEBUGCHK(pTransfer->dwUsbError == UFN_NOT_COMPLETE_ERROR);


		// Transfer is ready
		{
			PBYTE pbBuffer = (PBYTE) pTransfer->pvBuffer + pTransfer->cbTransferred;
			DWORD cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;


			volatile ULONG *pulFifoReg = _GetDataRegister(dwEndpoint);

			DWORD cbWritten = 0;
			WORD WriteData = 0;

			// Min of input byte count and supported size
			DWORD cbToWrite = min(cbBuffer, peps->dwPacketSizeAssigned);

			if (dwEndpoint == 0)
			{

				WriteIndexedReg(pContext, 0, BWCR, cbToWrite);

				for (cbWritten = 0; cbWritten < cbToWrite; cbWritten+=2)
				{
					WriteData=((*(pbBuffer+1))<<8) | *pbBuffer;
					*pulFifoReg = WriteData;
					pbBuffer +=2;
				}

				/* We can complete on a packet which is full. We need to wait till
				* next time and generate a zero length packet, so only complete
				* if we're at the end and it is not the max packet size.
				*/
				pTransfer->cbTransferred += cbToWrite;
				// We have to consider 16bit buffer interface
				if (pTransfer->cbTransferred == pTransfer->cbBuffer
				        && pTransfer->pvPddData == 0)
				{

					dwStatus = UFN_NO_ERROR;
					fCompleted = TRUE;
					pContext->Ep0State = EP0_STATE_IDLE;
				}

			}
			else
			{

				// Enable Interrupts before writing to the FIFO. This insures
				// That any interrupts generated because of the write will be
				// "latched"
				if (fEnableInterrupts)
				{
					DEBUGCHK(dwEndpoint != 0);
					EnableEndpointInterrupt(pContext, dwEndpoint);
				}

				// If Packet was completed in a previous interrupt cycle,
				// the data length to be txed will be zero, and
				// zero length data packet should not be transmitted
				if( cbToWrite != 0)
					WriteIndexedReg(pContext, dwEndpoint, BWCR, cbToWrite);
				;

				for (cbWritten = 0; cbWritten < cbToWrite; cbWritten+=2)
				{
					WriteData=((*(pbBuffer+1))<<8) | *pbBuffer;
					*pulFifoReg = WriteData;
					pbBuffer +=2;
				}


				// We have to consider 16bit buffer interface
				if (pTransfer->cbTransferred == pTransfer->cbBuffer
				        || cbWritten == 0)
				{
					dwStatus = UFN_NO_ERROR;
					fCompleted = TRUE;
				}

				// By Placing the check for packet complete here, before
				// cbTransferred is updated, there is a 1 interrupt cycle delay
				// That is complete is not declared until the data has actually
				// been ACKd (TPC set) by the host
				pTransfer->cbTransferred += cbToWrite;
			}
		}


	}
	else
	{
		// It is possible for an interrupt to come in while still in this
		// function for first pass of transfer. If this happens it is possible
		// to complete the transfer and have that interrupt be unnecessary
		// so... just ignore it.
		RETAILMSG(DBG, (_T("%s Not Transfer \r\n"),
		                pszFname));
		goto EXIT;
	}


	if (fCompleted)
	{
		// Disable transfer interrupts until another transfer is issued.
		if (peps->dwEndpointNumber != 0)
		{
			DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
		}

		RETAILMSG(DBG, (_T("%s Tx Done  Ep%x  Status %u\r\n"), pszFname,
		                dwEndpoint, dwStatus));
		CompleteTransfer(pContext, peps, dwStatus);
	}
	else
	{
		RETAILMSG(DBG, (_T("%s Tx EP%x BufferSize=%u, Xfrd=%u\r\n"),
		                pszFname, dwEndpoint, pTransfer->cbBuffer, pTransfer->cbTransferred));
	}

EXIT:
	FUNCTION_LEAVE_MSG();
#endif
}


VOID
HandleEndpoint0Event(
    PCTRLR_PDD_CONTEXT  pContext
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	ValidateContext(pContext);
	DEBUGCHK(pContext->fRunning);

	PEP_STATUS peps = GetEpStatus(pContext, 0);
	LOCK_ENDPOINT(peps);

	ClearEndpointInterrupt(pContext, 0);
	WORD bUSBBusIrqStat = ReadReg(pContext, SSR);
	WORD bEP0IrqStatus = ReadReg(pContext, EP0SR);
	WORD bSCR = ReadReg(pContext, SCR);
	WORD bEP0CR = ReadReg(pContext, EP0CR);

	// Write 0 to SEND_STALL and SENT_STALL to clear them, so we need to
	// leave them unchanged by default.
	BYTE bEp0CsrToWrite = 0;

	if(StallFlag)
	{
		RETAILMSG(1, (_T("1_after SendStall Int Gen : EP0SR:%08x bEP0CR : %08x==============\r\n"),bEP0IrqStatus,bEP0CR));
		StallFlag = FALSE;
	}


	// Set By USB if protocol violation detected
	if (bEP0IrqStatus & EP0SHT)
	{
		// Must Clear both Send and Sent Stall
		SetClearReg(pContext, EP0SR, EP0SHT, SET);
		SetClearReg(pContext, EP0CR, EP0ESS, CLEAR);
		if (bEP0IrqStatus & EP0RSR)
			SetClearReg(pContext, EP0SR, EP0RSR, SET);
		pContext->Ep0State = EP0_STATE_IDLE;
	}

	if (bEP0IrqStatus & EP0TST)
	{
		// Must Clear both Send and Sent Stall
		SetClearReg(pContext, EP0SR, EP0TST, SET);
	}


	BOOL fSendUdr = FALSE;

	DWORD cbFifo = ReadIndexedReg(pContext, 0, BRCR);
	BOOL fCompleted = FALSE;
	DWORD dwStatus;


	// setup packet
	if (pContext->Ep0State == EP0_STATE_IDLE)
	{
		if (bEP0IrqStatus & EP0RSR)
		{
			if (!pContext->fSpeedReported)
			{
				if(bUSBBusIrqStat && HSP)
				{
					pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_SPEED,
					                    BS_HIGH_SPEED);
				}
				else
				{
					pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_SPEED,
					                    BS_FULL_SPEED);
				}
				pContext->fSpeedReported = TRUE;
			}

			// New setup packet
			const DWORD cbOutFifo = ReadIndexedReg(pContext, 0, BRCR);

			// 16bit Buffer Interface
			PWORD pbUdr = (PWORD) &pContext->udr;
			volatile ULONG *pulFifoReg = _GetDataRegister(0);

			DWORD cbBytesRemaining = cbOutFifo;
			while (cbBytesRemaining--)
			{
				*pbUdr = (WORD) *pulFifoReg;
				pbUdr ++;
			}

			SetClearReg(pContext, EP0SR, EP0RSR, SET);


			// Determine if this is a NO Data Packet
			if (pContext->udr.wLength > 0)
			{
				// Determine transfer Direction
				if (pContext->udr.bmRequestType & USB_ENDPOINT_DIRECTION_MASK)
				{
					// Start the SW OUT State Machine
					pContext->Ep0State = EP0_STATE_IN_DATA_PHASE;
					RETAILMSG(DBG, (_T("%s EP0_STATE_IN_DATA_PHASE\r\n"), pszFname));
				}
				else
				{
					// Start the SW OUT State Machine
					pContext->Ep0State = EP0_STATE_OUT_DATA_PHASE;
					RETAILMSG(DBG, (_T("%s EP0_STATE_OUT_DATA_PHASE\r\n"), pszFname));
				}

				pContext->sendDataEnd = FALSE;
			}
			else
			{ // udr.wLength == 0
				// ClientDriver will issue a SendControlStatusHandshake to
				// complete the transaction.
				pContext->sendDataEnd = TRUE;

				// Nothing left to do... stay in IDLE.
				DEBUGCHK(pContext->Ep0State == EP0_STATE_IDLE);
			}

			fSendUdr = TRUE;
		}
		else
		{
			WriteIndexedReg(pContext, 0, EP0SR, bEP0IrqStatus);//for RNDIS Class, adkim
		}
	}
	// Data Out Packet
	else if (pContext->Ep0State == EP0_STATE_OUT_DATA_PHASE)
	{
		if (bEP0IrqStatus & EP0RSR)
		{

			// Check For out packet read && receive fifo not empty -> out token event
			if (cbFifo)
			{
				DEBUGMSG(ZONE_RECEIVE, (_T("%s out token packet on endpoint 0 \r\n"),
				                        pszFname));
				HandleRx(pContext, peps, &fCompleted, &dwStatus);
			}
			// status stage of control transfer; zero-length packet received
			else
			{
				DEBUGMSG(ZONE_RECEIVE, (_T("%s status stage of control transfer on endpoint 0\r\n"),
				                        pszFname));
				pContext->Ep0State = EP0_STATE_IDLE;
			}
		}
		else
			RETAILMSG(DBG, (_T("Not RST in outdataphase: 0x%08x =========\r\n"),bEP0IrqStatus ));
	}
	// Data In Packet
	else
	{

		HandleTx(pContext, peps, 0);
	}


	if (fCompleted)
	{
		CompleteTransfer(pContext, peps, dwStatus);
	}

	if (fSendUdr)
	{
		pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &pContext->udr);
	}


	FUNCTION_LEAVE_MSG();
	UNLOCK_ENDPOINT(peps);
}

#define DBG_TEST3 1
// Process an endpoint interrupt.  Call interrupt-specific handler.
static
VOID
HandleEndpointEvent(
    PCTRLR_PDD_CONTEXT  pContext,
    DWORD               dwEndpoint,
    DWORD               epIrqStat
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	ValidateContext(pContext);
	DEBUGCHK(pContext->fRunning);
	DEBUGCHK(dwEndpoint != 0);

	DWORD dwPendingEvents = 0;
	EP_STATUS *peps = GetEpStatus(pContext, dwEndpoint);
	PREFAST_DEBUGCHK(peps);

	LOCK_ENDPOINT(peps);

	ClearEndpointInterrupt(pContext, dwEndpoint);

	WORD bEpIrqStat;
	bEpIrqStat = ReadIndexedReg(pContext, dwEndpoint, ESR);

	if (peps->dwDirectionAssigned == USB_IN_TRANSFER)
	{
		// Stall "acknowledged" from Host
		if (bEpIrqStat & FSC)
		{
			USB_DEVICE_REQUEST udr;
			udr.bmRequestType = USB_REQUEST_FOR_ENDPOINT;
			udr.bRequest = USB_REQUEST_CLEAR_FEATURE;
			udr.wValue = USB_FEATURE_ENDPOINT_STALL;
			udr.wIndex = USB_ENDPOINT_DIRECTION_MASK | (BYTE) dwEndpoint;
			udr.wLength = 0;

			DisableEndpointInterrupt(pContext, dwEndpoint);

			DEBUGMSG(ZONE_PIPE, (_T("%s Got IN_SENT_STALL EP%u \r\n"),
			                     pszFname, dwEndpoint));


			pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &udr);
			// Must Clear both Send and Sent Stall
			SetClearIndexedReg(pContext, dwEndpoint, ESR, FSC, SET);
		}

		if (bEpIrqStat & TPS)
		{
			// Must Clear Tx Packet Success
			WriteIndexedReg(pContext, dwEndpoint, ESR, bEpIrqStat);
		}

		if( !(bEpIrqStat & (0x1 << 2)))
		{
			dwPendingEvents = IN_TRANSFER;
		}
	}
	else
	{
		// Stall "acknowledged" from Host
		if (bEpIrqStat & FSC)
		{
			USB_DEVICE_REQUEST udr;
			udr.bmRequestType = USB_REQUEST_FOR_ENDPOINT;
			udr.bRequest = USB_REQUEST_CLEAR_FEATURE;
			udr.wValue = USB_FEATURE_ENDPOINT_STALL;
			PREFAST_SUPPRESS(12006, "Buffer access index expression 'udr.wIndex=(USHORT)dwEndpoint' is being truncated in a shortening cast.");
			udr.wIndex = (USHORT) dwEndpoint;
			udr.wLength = 0;

			DisableEndpointInterrupt(pContext, dwEndpoint);

			DEBUGMSG(ZONE_PIPE, (_T("%s Got OUT_SENT_STALL EP%u \r\n"),
			                     pszFname, dwEndpoint));


			pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &udr);
			// Must Clear both Send and Sent Stall
			SetClearIndexedReg(pContext, dwEndpoint, ESR, FSC, SET);
		}

		if (bEpIrqStat & FFS)
		{
			// Must Clear FIFO Flushed
			SetClearReg(pContext, ESR, FFS, SET);
		}
		if (bEpIrqStat & RPS)
		{
			// Rx Packet Success is automatically cleared when MCU reads all packets
			dwPendingEvents = OUT_TRANSFER;
		}

	}

	BOOL fCompleted = FALSE;
	DWORD dwStatus;

	if (dwPendingEvents == IN_TRANSFER)
	{
		HandleTx(pContext, peps, 0);
	}

	else if (dwPendingEvents == OUT_TRANSFER)
	{
		HandleRx(pContext, peps, &fCompleted, &dwStatus);
	}

	if (fCompleted)
	{
		// Disable transfer interrupts until another transfer is issued.
		DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
	}

	if (fCompleted)
	{
		CompleteTransfer(pContext, peps, dwStatus);
	}


	FUNCTION_LEAVE_MSG();
	UNLOCK_ENDPOINT(peps);
}


// Process USB Bus interrupt
VOID
HandleUSBBusIrq(
    PCTRLR_PDD_CONTEXT  pContext,
    WORD                bUSBBusIrqStat
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	if (bUSBBusIrqStat & VBUSON)
	{
		SetClearReg(pContext, SSR, VBUSON, SET);
	}

	if (bUSBBusIrqStat & SSRINTERR)
	{
		SetClearReg(pContext, SSR, SSRINTERR, SET);
	}

	if (bUSBBusIrqStat & SDE)
	{
		SetClearReg(pContext, SSR, SDE, SET);
		if(bUSBBusIrqStat & HSP)
		{
			RETAILMSG(1, (_T("HIGH Speed\r\n")));
		}
		else
		{
			RETAILMSG(1, (_T("FULL Speed\r\n")));
		}
	}



	if (bUSBBusIrqStat & HFSUSP)
	{
		SetClearReg(pContext, SSR, HFSUSP, SET);

		SetClearReg(pContext, SCR, HSUSPE, CLEAR);

		SetClearReg(pContext, SCR, (RRDE | MFRM), SET);

		RETAILMSG(1, (_T("%s Suspend\r\n"), pszFname));
		if (pContext->attachedState == UFN_ATTACH)
		{
			DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Suspend\r\n"), pszFname));
			RETAILMSG(1, (_T("%s Suspend_Detach\r\n"), pszFname));
			pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_DETACH);
			pContext->attachedState = UFN_DETACH;
		}
	}

	if (bUSBBusIrqStat & HFRM)
	{
		SetClearReg(pContext, SSR, HFRM, SET);

		SetClearReg(pContext, SCR, MFRM, CLEAR);

		// Enable suspend interrupt
		SetClearReg(pContext, SCR, (RRDE | HSUSPE), SET);


		RETAILMSG(1, (_T("%s Resume\r\n"), pszFname));
		if (pContext->attachedState == UFN_DETACH)
		{
			DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Resume\r\n"), pszFname));
			RETAILMSG(1, (_T("%s Resume_Attach\r\n"), pszFname));
			//Sleep(1000); //for MSF Class,kimsh,  on booting, to generate SD Detect INT and to to mount before storage detectetcion on BOT
			pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_ATTACH);
			pContext->attachedState = UFN_ATTACH;
		}
	}

	if (bUSBBusIrqStat & HFRES)
	{
		SetClearReg(pContext, SSR, HFRES, SET);

		DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Reset\r\n"), pszFname));

		pContext->fSpeedReported = FALSE;

		RETAILMSG(1, (_T("%s Reset\r\n"), pszFname));

		if (pContext->attachedState == UFN_DETACH)
		{
			RETAILMSG(1, (_T("%s Reset_Attach\r\n"), pszFname));
			pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_ATTACH);
			pContext->attachedState = UFN_ATTACH;
		}

		pContext->Ep0State = EP0_STATE_IDLE;
		pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESET);

	}

	FUNCTION_LEAVE_MSG();
}


// Process a SC2443 interrupt.

VOID
HandleUSBEvent(
    PCTRLR_PDD_CONTEXT pContext
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();
	ValidateContext(pContext);

	//by shkim
	WORD nStop = FALSE;
	WORD bEpIrqStat = ReadReg(pContext, EIR);
	WORD bUSBBusIrqStat = ReadReg(pContext, SSR);

	WORD bSCR = ReadReg(pContext, SCR);


	//  while (bEpIrqStat || bUSBBusIrqStat) {
	if (bUSBBusIrqStat)
	{
		HandleUSBBusIrq(pContext, bUSBBusIrqStat);
		// after notifying, must wait 10ms., by shkim
		// if there is no this code, EP0 Stall is generated and usb connection is failed
		// So, this code is workaround code for usb connection
		//   Sleep(10);
	}

	if (bEpIrqStat)
	{

		if (bEpIrqStat & EP0I)
		{
			HandleEndpoint0Event(pContext);
		}
		else //add by shkim
		{
			// Process All Other (besides EP0) Endpoints
			for (DWORD dwEndpoint = 1; dwEndpoint < ENDPOINT_COUNT; ++dwEndpoint)
			{
				// Check the Interrupt Mask
				// Check the Interrupt Status
				BYTE bEpBit =  EpToIrqStatBit(dwEndpoint);
				if (bEpIrqStat & bEpBit)
				{
					HandleEndpointEvent(pContext, dwEndpoint, bEpIrqStat);
					nStop = TRUE; 		//by shkim
				}
				if(nStop)
					break;
			}
		}
	}

	// after notifying, must wait 10ms., by shkim
	// if there is no this code, EP0 Stall is generated and usb connection is failed
	// So, this code is workaround code for usb connection
	//Sleep(15);

	FUNCTION_LEAVE_MSG();
}


/****************************************************************
@doc INTERNAL
 
@func VOID | SerUSB_InternalMapRegisterAddresses |
This routine maps the ASIC registers. 
It's an artifact of this
implementation.
 
@rdesc None.
****************************************************************/

DWORD MapRegisterSet(PCTRLR_PDD_CONTEXT pContext)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	DWORD   dwRet = ERROR_SUCCESS;

	g_pUDCBase =(BYTE *)OALPAtoVA(S3C2443_BASE_REG_PA_USBD, FALSE);

	FUNCTION_LEAVE_MSG();

	return dwRet;
}


// interrupt service routine.
#if 0
DWORD
WINAPI
ISTMain(
    LPVOID lpParameter
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) lpParameter;
	ValidateContext(pContext);

	CeSetThreadPriority(pContext->hIST, pContext->dwISTPriority);


	while (!pContext->fExitIST)
	{
		pContext->fRestartIST = FALSE;

		// Disable All Endpoint interrupts
		WriteReg(pContext, EIER, 0); // Disable All

		//kim sang hee.
		//Resume signal is occured when cable is not connected
		//So, MFRM is setted by '0'

		// Enable Device interrupts
		//    SetClearReg(pContext, SCR, (RRDE | HRESE | HSUSPE | MFRM), SET);
		SetClearReg(pContext, SCR, (RRDE|HRESE|HSUSPE), SET);

		SetClearReg(pContext, SSR,  (HFRES | HFSUSP | HFRM), SET);

		// Enable Endpoint interrupt 0
		EnableEndpointInterrupt(pContext, 0);

		while (TRUE)
		{
			DWORD dwWait = WaitForSingleObject(pContext->hevInterrupt, INFINITE);
			if (pContext->fExitIST || pContext->fRestartIST)
			{
				break;
			}

			if (dwWait == WAIT_OBJECT_0)
			{
				HandleUSBEvent(pContext);
				InterruptDone(pContext->dwSysIntr);
			}
			else
			{
				RETAILMSG(DBG, (_T("%s WaitForMultipleObjects failed. Exiting IST.\r\n"),
				                pszFname));
				break;
			}
		}
		// Send detach
		pContext->pfnNotify(pContext->pvMddContext,
		                    UFN_MSG_BUS_EVENTS, UFN_DETACH);

		pContext->fSpeedReported = FALSE;
		pContext->attachedState = UFN_DETACH;
		RETAILMSG(1, (_T("UFN_DETACH_2\r\n")));

		// Disable Device  interrupts - write Zeros to Disable
		SetClearReg(pContext, SCR, (HRESE | HSUSPE | MFRM), CLEAR);

		// Disable endpoint interrupts - write Zeros to Disable
		WriteReg(pContext, EIER, 0);

		// Clear any outstanding device & endpoint interrupts
		// USB Device Interrupt Status - Write a '1' to Clear
		SetClearReg(pContext, SSR,  (HFRES | HFSUSP | HFRM), SET);
		// End point Interrupt Status - Write a '1' to Clear
		WriteReg(pContext, EIR, CLEAR_ALL_EP_INTRS);



	}

	FUNCTION_LEAVE_MSG();

	return 0;
}
#endif



extern "C" void  KUSBInterruptThread(PCTRLR_PDD_CONTEXT pContext)
{
	UINT32 mask;
	S3C2443_INTR_REG*g_pIntrRegs = (S3C2443_INTR_REG*)OALPAtoVA(
       S3C2443_BASE_REG_PA_INTR, FALSE);
	HandleUSBEvent(&g_pdd);
	//IPLIntrDoneIrq(IRQ_USBD);
	mask = 1 << IRQ_USBD;
	OUTREG32(&g_pIntrRegs->SRCPND, mask);
	CLRREG32(&g_pIntrRegs->INTMSK, mask);
}

extern "C" void KitlUSBISR()
{
	UINT32 start,end;
	S3C2443_INTR_REG*g_pIntrRegs = (S3C2443_INTR_REG*)OALPAtoVA(S3C2443_BASE_REG_PA_INTR, FALSE);

	while(!(INREG32(&g_pIntrRegs->SRCPND)&IRQ_USBD))
#if 0	
	{
		start=OALGetTickCount();
		while(OALGetTickCount()-start<1000);
		RETAILMSG(DBG, (_T("ISR timeout\r\n")));
	}
#else
{
	KUSBInterruptThread(NULL);
}
#endif
	
}

static
VOID
StartTransfer(
    PCTRLR_PDD_CONTEXT pContext,
    PEP_STATUS peps,
    PSTransfer pTransfer
)
{
	SETFNAME();

	DEBUGCHK(pContext);
	PREFAST_DEBUGCHK(peps);

	DEBUGCHK(!peps->pTransfer);
	ValidateTransferDirection(pContext, peps, pTransfer);

	LOCK_ENDPOINT(peps);
	FUNCTION_ENTER_MSG();

	RETAILMSG(DBG, (_T("%s Setting up %s transfer on ep %u for %u bytes\r\n"),
	                pszFname, (pTransfer->dwFlags == USB_IN_TRANSFER) ? _T("in") : _T("out"),
	                peps->dwEndpointNumber, pTransfer->cbBuffer));

	// Enable transfer interrupts.
	peps->pTransfer = pTransfer;
	DWORD dwEndpoint = peps->dwEndpointNumber;

	if (pTransfer->dwFlags == USB_IN_TRANSFER)
	{

		if (peps->dwEndpointNumber == 0)
		{

			WORD bEp0ESR = ReadReg(pContext, EP0SR);
			if (bEp0ESR & EP0TST)
				WriteReg(pContext, EP0SR, bEp0ESR);

			HandleTx(pContext, peps, 0);
		}
		else
		{
			WORD bEpESR = ReadIndexedReg(pContext, dwEndpoint, ESR);
			if (bEpESR & TPS)
			{
				WriteIndexedReg(pContext, dwEndpoint, ESR, bEpESR);
			}
			HandleTx(pContext, peps, 1);
		}
	}
	else
	{
		if (peps->dwEndpointNumber == 0)
		{}
		else
		{
			EnableEndpointInterrupt(pContext, peps->dwEndpointNumber);

			// There may be a packet available.  If so process it...
			WORD bEpIrqStat = ReadIndexedReg(pContext, peps->dwEndpointNumber, ESR);

			if (bEpIrqStat & RPS)
			{
				BOOL fCompleted;
				DWORD dwStatus;
				HandleRx(pContext, peps, &fCompleted, &dwStatus);

				if (fCompleted)
				{
					// Disable transfer interrupts until another transfer is issued.
					DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
				}


				if (fCompleted)
				{
					CompleteTransfer(pContext, peps, dwStatus);
				}
			}
		}
	}

	FUNCTION_LEAVE_MSG();

	UNLOCK_ENDPOINT(peps);
}
DWORD
WINAPI
UfnPdd_IssueTransfer(
    PVOID  pvPddContext,
    DWORD  dwEndpoint,
    PSTransfer pTransfer
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	DEBUGCHK(EP_VALID(dwEndpoint));

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);
	LOCK_ENDPOINT(peps);
	DEBUGCHK(peps->fInitialized);
	DEBUGCHK(pTransfer->cbTransferred == 0);

	DWORD dwRet = ERROR_SUCCESS;

	RETAILMSG(DBG, (_T("%s  UfnPdd_IssueTransfer\r\n"),
	                pszFname));

	// Note For the HW NAKs IN requests and DOES NOT let SW
	// know that the Host is trying to send a request. SO... Start the Transfer
	// In Now!
	// Start the Transfer
	DEBUGCHK(peps->pTransfer == NULL);
	StartTransfer(pContext, peps, pTransfer);

	UNLOCK_ENDPOINT(peps);

	FUNCTION_LEAVE_MSG();

	return dwRet;
}


DWORD
WINAPI
UfnPdd_AbortTransfer(
    PVOID           pvPddContext,
    DWORD           dwEndpoint,
    PSTransfer      pTransfer
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	PREFAST_DEBUGCHK(pTransfer);
	DEBUGCHK(EP_VALID(dwEndpoint));

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);
	LOCK_ENDPOINT(peps);
	DEBUGCHK(peps->fInitialized);

	RETAILMSG(DBG, (_T("%s  UfnPdd_AbortTransfer\r\n"),
	                pszFname));

	ValidateTransferDirection(pContext, peps, pTransfer);

	DEBUGCHK(pTransfer == peps->pTransfer);
	CompleteTransfer(pContext, peps, UFN_CANCELED_ERROR);

	if (dwEndpoint == 0)
	{
		pContext->Ep0State = EP0_STATE_IDLE;
	}

	ResetEndpoint( pContext,peps);

	UNLOCK_ENDPOINT(peps);

	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}


/////////////////////////////// jassi ////////////////////////////////
#define CLKCON_USBD (1<<7)

volatile S3C2443_CLKPWR_REG *pCLKPWR	= NULL;		// Clock power registers (needed to enable I2S and SPI clocks)
volatile S3C2443_IOPORT_REG *pIOPregs	= NULL;

BOOL HW_USBClocks(CEDEVICE_POWER_STATE    cpsNew)
{

	RETAILMSG(DBG, (_T("HW_USBClocks\r\n")));
	DWORD time;

	pCLKPWR = (volatile S3C2443_CLKPWR_REG*)(S3C2443_CLKPWR_REG *)OALPAtoVA(S3C2443_BASE_REG_PA_CLOCK_POWER, FALSE);
	pIOPregs = (volatile S3C2443_IOPORT_REG *)(S3C2443_IOPORT_REG *)OALPAtoVA(S3C2443_BASE_REG_PA_IOPORT, FALSE);


	if (cpsNew == D0)
	{
		RETAILMSG(DBG, (TEXT("HW_USBClocks::D0 \r\n")));

		//Enable USB power
		pIOPregs->GPACDL &= ~(0x1<<13);
		pIOPregs->GPACDL |= (0x1<<12);

		// Set the Normal mode
		pIOPregs->GPHCON = (pIOPregs->GPHCON & ~(0x3<<28)) | (0x1<<28);
		pIOPregs->GPHUDP = (pIOPregs->GPHUDP & ~(0x3<<28));
		pIOPregs->GPHDAT = (pIOPregs->GPHDAT & ~(0x1<<14)) | (0x1<<14);

		//
		pIOPregs->MISCCR &= ~(1<<12);
		// Enable the PHY Power
		pCLKPWR->PWRCFG |= (1<<4);
		// First USB PHY has to be reset, and after 10us, func and host has to be reset.
		pCLKPWR->USB_RSTCON = (0<<2)|(0<<1)|(1<<0);
		time=OALGetTickCount();
		while(OALGetTickCount()-time<1000)
			;
		pCLKPWR->USB_RSTCON = (1<<2)|(1<<1)|(0<<0);
		pCLKPWR->USB_RSTCON = (0<<2)|(0<<1)|(0<<0);
		// Set USB PHY Control
		// Ref. Clock (48MHz), Clock (X-tal), Host Clock (Ext. X-tal), D-stream (Device Mode)
		pCLKPWR->USB_PHYCTRL = (0<<3)|(0<<2)|(0<<1)|(0<<0);
		// Set USB PHY Power
		// 48Mhz clock on ,PHY2.0 analog block power on,XO block power on,
		// XO block power in suspend mode,PHY 2.0 Pll power on ,suspend signal for save mode disable
		pCLKPWR->USB_PHYPWR =  (0x1<<31)|(0x0<<4)|(0x0<<3)|(0x0<<2)|(0x0<<1)|(0x0<<0);
		// Set USB Clock Control
		// Vbus detect enable and D+ Pull up, USB2.0 Function clock Enable,
		// USB1.1 HOST disable,USB2.0 PHY test enable
		pCLKPWR->USB_CLKCON = (1<<31)|(1<<2)|(0<<1)|(0<<0);

	}
	// Should be implemented
	else if (cpsNew == D4)
	{
		RETAILMSG(DBG, (TEXT("HW_USBClocks::D4 \r\n")));
		// Set the Normal mode
		pIOPregs->GPHCON = (pIOPregs->GPHCON & ~(0x3<<28)) | (0x1<<28);
		pIOPregs->GPHUDP = (pIOPregs->GPHUDP & ~(0x3<<28)) | (0x2<<28);
		pIOPregs->GPHDAT = (pIOPregs->GPHDAT & ~(0x1<<14));
		pIOPregs->MISCCR |= (1<<12);
		// Enable the PHY Power
		pCLKPWR->PWRCFG |= (1<<4);
		// First USB PHY has to be reset, and after 10us, func and host has to be reset.
		pCLKPWR->USB_RSTCON = (0<<2)|(0<<1)|(1<<0);
		//Visual: Sleep(1);
		pCLKPWR->USB_RSTCON = (1<<2)|(1<<1)|(0<<0);
		pCLKPWR->USB_RSTCON = (0<<2)|(0<<1)|(0<<0);
		// Set USB PHY Control
		// Ref. Clock (48MHz), Clock (X-tal), Host Clock (Ext. X-tal), D-stream (Device Mode)
		pCLKPWR->USB_PHYCTRL = (0<<3)|(1<<2)|(0<<1)|(0<<0);
		// Set USB PHY Power
		// 48Mhz clock on ,PHY2.0 analog block power on,XO block power on,
		// XO block power in suspend mode,PHY 2.0 Pll power on ,suspend signal for save mode disable
		pCLKPWR->USB_PHYPWR = (0<<31)|(1<<4)|(0<<3)|(0<<2)|(0<<1)|(0<<0);
		// Set USB Clock Control
		// Vbus detect enable and D+ Pull up, USB2.0 Function clock Enable,
		// USB1.1 HOST disable,USB2.0 PHY test enable
		pCLKPWR->USB_CLKCON = (1<<31)|(1<<2)|(0<<1)|(0<<0);
	}

	return TRUE;
}


DWORD
WINAPI
UfnPdd_Deinit(
    PVOID pvPddContext
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}

DWORD
WINAPI
UfnPdd_ClearEndpointStall(
    PVOID pvPddContext,
    DWORD dwEndpoint
);

DWORD
WINAPI
UfnPdd_Start(
    PVOID        pvPddContext
)
{
	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT)pvPddContext;
	SETFNAME();
	FUNCTION_ENTER_MSG();
	//HW_USBClocks(D0);
	/////////////////////////////////////////////////
	//endpoint 0
	PEP_STATUS peps = GetEpStatus(pContext, 0);
	peps->dwPacketSizeAssigned = 64;
	peps->fInitialized = TRUE;

	/////////////////////////////////////////////////
	//endpoint 1,IN
	peps = GetEpStatus(pContext, 1);
	SetClearReg(pContext, EDR, (0x1 << 1), SET);
	peps->dwDirectionAssigned = USB_IN_TRANSFER;
	WriteIndexedReg(pContext, 1, ECR, 0x0000);
	ResetEndpoint(pContext,peps);
	//Bulk
	SetClearIndexedReg(pContext, 1,ECR,IME, CLEAR);
	peps->dwEndpointType = USB_ENDPOINT_TYPE_BULK;
	peps->dwPacketSizeAssigned = 512;
	// Set the Max Packet Register
	WriteIndexedReg(pContext, 1, MPR, 512);
	UfnPdd_ClearEndpointStall(pContext ,1);
	// Clear outstanding interrupts
	ClearEndpointInterrupt(pContext, 1);
	peps->fInitialized = TRUE;

	/////////////////////////////////////////////////
	//endpoint 2,OUT
	peps = GetEpStatus(pContext, 2);
	SetClearReg(pContext, EDR, (0x1 << 2), CLEAR);
	peps->dwDirectionAssigned = USB_OUT_TRANSFER;
	WriteIndexedReg(pContext, 2, ECR, 0x0080);
	WORD bECR = ReadIndexedReg(pContext,2, ECR);
	ResetEndpoint(pContext,peps);
	//Bulk
	SetClearIndexedReg(pContext, 2,ECR,IME, CLEAR);
	peps->dwEndpointType = USB_ENDPOINT_TYPE_BULK;
	peps->dwPacketSizeAssigned = 512;
	// Set the Max Packet Register
	WriteIndexedReg(pContext, 2, MPR, 512);
	UfnPdd_ClearEndpointStall(pContext ,3);
	// Clear outstanding interrupts
	ClearEndpointInterrupt(pContext, 2);
	peps->fInitialized = TRUE;
	
	/////////////////////////////////////////////////
	//endpoint 3,IN
	peps = GetEpStatus(pContext, 3);
	SetClearReg(pContext, EDR, (0x1 << 3), SET);
	peps->dwDirectionAssigned = USB_IN_TRANSFER;
	WriteIndexedReg(pContext, 3, ECR, 0x0000);
	ResetEndpoint(pContext,peps);
	//Bulk
	SetClearIndexedReg(pContext, 3,ECR,IME, CLEAR);
	peps->dwEndpointType = USB_ENDPOINT_TYPE_INTERRUPT;
	peps->dwPacketSizeAssigned = 8;
	// Set the Max Packet Register
	WriteIndexedReg(pContext, 3, MPR, 8);
	UfnPdd_ClearEndpointStall(pContext ,3);
	// Clear outstanding interrupts
	ClearEndpointInterrupt(pContext, 3);
	peps->fInitialized = TRUE;
	
	/////////////////////////////////////////////////
	// Disable All Endpoint interrupts
	WriteReg(pContext, EIER, 0); // Disable All

	// Enable Device interrupts
	SetClearReg(pContext, SCR, (RRDE|HRESE|HSUSPE), SET);

	SetClearReg(pContext, SSR,  (HFRES | HFSUSP | HFRM), SET);

	// Enable Endpoint interrupt 0
	EnableEndpointInterrupt(pContext, 0);

	FUNCTION_LEAVE_MSG();

	return TRUE;
}


// Stop the device.
DWORD
WINAPI
UfnPdd_Stop(
    PVOID pvPddContext
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();


	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}


DWORD
WINAPI
UfnPdd_IsConfigurationSupportable(
    PVOID                       pvPddContext,
    UFN_BUS_SPEED               Speed,
    PUFN_CONFIGURATION          pConfiguration
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	RETAILMSG(DBG, (_T("%s  UfnPdd_IsConfigurationSupportable\r\n"),
	                pszFname));

	DEBUGCHK((Speed == BS_FULL_SPEED) | (Speed == BS_HIGH_SPEED));

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	// This PDD does not have any special requirements that cannot be
	// handled through IsEndpointSupportable.
	DWORD dwRet = ERROR_SUCCESS;

	FUNCTION_LEAVE_MSG();

	return dwRet;
}


//
// Is this endpoint supportable.
DWORD
WINAPI
UfnPdd_IsEndpointSupportable(
    PVOID                       pvPddContext,
    DWORD                       dwEndpoint,
    UFN_BUS_SPEED               Speed,
    PUSB_ENDPOINT_DESCRIPTOR    pEndpointDesc,
    BYTE                        bConfigurationValue,
    BYTE                        bInterfaceNumber,
    BYTE                        bAlternateSetting
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	RETAILMSG(DBG, (_T("%s  UfnPdd_IsEndpointSupportable\r\n"),
	                pszFname));

	DEBUGCHK(EP_VALID(dwEndpoint));
	DEBUGCHK((Speed == BS_FULL_SPEED) | (Speed == BS_HIGH_SPEED));

	DWORD dwRet = ERROR_SUCCESS;
	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);

	// Special case for endpoint 0
	if (dwEndpoint == 0)
	{
		DEBUGCHK(pEndpointDesc->bmAttributes == USB_ENDPOINT_TYPE_CONTROL);

		// Endpoint 0 only supports 8 or 16 byte packet size
		if (pEndpointDesc->wMaxPacketSize < EP_0_PACKET_SIZE)
		{
			RETAILMSG(DBG, (_T("%s Endpoint 0 only supports %u byte packets\r\n"),
			                pszFname, EP_0_PACKET_SIZE));
			dwRet = ERROR_INVALID_PARAMETER;
		}
		else
		{
			// Larger than EP 0 Max Packet Size - reduce to Max
			pEndpointDesc->wMaxPacketSize = EP_0_PACKET_SIZE;
		}
	}
	else if (dwEndpoint < ENDPOINT_COUNT)
	{
		BYTE bTransferType = pEndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
		DEBUGCHK(bTransferType != USB_ENDPOINT_TYPE_CONTROL);

		// Validate and adjust packet size
		WORD wPacketSize =
		    (pEndpointDesc->wMaxPacketSize & USB_ENDPOINT_MAX_PACKET_SIZE_MASK);

		switch(bTransferType)
		{

			// Isoch not currently supported by Samsung HW
		case USB_ENDPOINT_TYPE_ISOCHRONOUS:
			RETAILMSG(DBG, (_T("%s Isochronous endpoints are not supported\r\n"),
			                pszFname));
			dwRet = ERROR_INVALID_PARAMETER;
			break;

		case USB_ENDPOINT_TYPE_BULK:
		case USB_ENDPOINT_TYPE_INTERRUPT:
			// HW Can only Support 8, 16, 32, 64 byte packets
			if((wPacketSize >= 8) && (wPacketSize < 16))
			{
				wPacketSize = 8;
			}
			else if ((wPacketSize >= 16) && (wPacketSize < 32))
			{
				wPacketSize = 16;
			}
			else if((wPacketSize >= 32) && (wPacketSize < 64))
			{
				wPacketSize = 32;
			}
			else if ((wPacketSize >= 64) && (wPacketSize < 128))
			{
				wPacketSize = 64;
			}
			else if((wPacketSize >= 128) && (wPacketSize < 256))
			{
				wPacketSize = 128;
			}
			else if ((wPacketSize >= 256) && (wPacketSize < 512))
			{
				wPacketSize = 256;
			}
			else if (wPacketSize >= 512)
			{
				wPacketSize = 512;
			}
			else
			{ // wPacketSize < 8
				dwRet = ERROR_INVALID_PARAMETER;
			}
			break;

		default:
			dwRet = ERROR_INVALID_PARAMETER;
			break;
		}

		// If Requested Size is larger than what is supported ... change it.
		// Note only try and change it if no errors so far... meaning Ep is
		// Supportable.
		if ( (wPacketSize != (pEndpointDesc->wMaxPacketSize & USB_ENDPOINT_MAX_PACKET_SIZE_MASK)) &&
		        (dwRet == ERROR_SUCCESS) )
		{
			pEndpointDesc->wMaxPacketSize &= ~USB_ENDPOINT_MAX_PACKET_SIZE_MASK;
			pEndpointDesc->wMaxPacketSize |= wPacketSize;
		}

	}

	FUNCTION_LEAVE_MSG();

	return dwRet;
}


// Clear an endpoint stall.
DWORD
WINAPI
UfnPdd_ClearEndpointStall(
    PVOID pvPddContext,
    DWORD dwEndpoint
)
{
	DWORD dwRet = ERROR_SUCCESS;

	SETFNAME();
	FUNCTION_ENTER_MSG();


	DEBUGCHK(EP_VALID(dwEndpoint));

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);
	LOCK_ENDPOINT(peps);

	if(dwEndpoint ==0)
		RETAILMSG(1, (_T("%s  UfnPdd_ClearEndpointStall, EP : %d, \r\n"), pszFname,dwEndpoint));

	if (dwEndpoint == 0)
	{
		// Must Clear both Transmitted Stall and Stall Set
		SetClearReg(pContext, EP0SR, EP0SHT, SET);
		SetClearReg(pContext, EP0CR, EP0ESS, CLEAR);
	}
	else
	{
		// Must Clear both Send and Sent Stall
		SetClearIndexedReg(pContext, dwEndpoint, ECR, ESS, SET);
		SetClearIndexedReg(pContext, dwEndpoint, ECR, ESS, CLEAR);
		SetClearIndexedReg(pContext ,dwEndpoint, ESR, FSC, SET);
	}



	UNLOCK_ENDPOINT(peps);
	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}


// Initialize an endpoint.
DWORD
WINAPI
UfnPdd_InitEndpoint(
    PVOID                       pvPddContext,
    DWORD                       dwEndpoint,
    UFN_BUS_SPEED               Speed,
    PUSB_ENDPOINT_DESCRIPTOR    pEndpointDesc,
    PVOID                       pvReserved,
    BYTE                        bConfigurationValue,
    BYTE                        bInterfaceNumber,
    BYTE                        bAlternateSetting
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	DEBUGCHK(EP_VALID(dwEndpoint));
	PREFAST_DEBUGCHK(pEndpointDesc);

	RETAILMSG(DBG, (_T("%s  UfnPdd_InitEndpoint\r\n"),
	                pszFname));

#ifdef DEBUG

	{
		USB_ENDPOINT_DESCRIPTOR EndpointDesc;
		memcpy(&EndpointDesc, pEndpointDesc, sizeof(EndpointDesc));
		DEBUGCHK(UfnPdd_IsEndpointSupportable(pvPddContext, dwEndpoint, Speed,
		                                      &EndpointDesc, bConfigurationValue, bInterfaceNumber,
		                                      bAlternateSetting) == ERROR_SUCCESS);
		DEBUGCHK(memcmp(&EndpointDesc, pEndpointDesc, sizeof(EndpointDesc)) == 0);
	}
#endif

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);
	BYTE bEndpointAddress = 0;

	PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);
	DEBUGCHK(!peps->fInitialized);


	WORD wMaxPacketSize =
	    pEndpointDesc->wMaxPacketSize & USB_ENDPOINT_MAX_PACKET_SIZE_MASK;
	DEBUGCHK(wMaxPacketSize);

	// If the target is endpoint 0, then only allow the function driver
	// to register a notification function.
	if (dwEndpoint == 0)
	{
		peps->dwPacketSizeAssigned = wMaxPacketSize;
		// Interrupts for endpoint 0 are enabled in ISTMain
	}
	else if (dwEndpoint < ENDPOINT_COUNT)
	{
		// Setup Direction (mode_in bit)
		bEndpointAddress = pEndpointDesc->bEndpointAddress;
		BOOL fModeOut = USB_ENDPOINT_DIRECTION_OUT(bEndpointAddress);
		if (fModeOut)
		{
			SetClearReg(pContext, EDR, (0x1 << dwEndpoint), CLEAR);
			peps->dwDirectionAssigned = USB_OUT_TRANSFER;

			WriteIndexedReg(pContext, dwEndpoint, ECR, 0x0080);
			WORD bECR = ReadIndexedReg(pContext, dwEndpoint, ECR);

		}
		else
		{
			SetClearReg(pContext, EDR, (0x1 << dwEndpoint), SET);
			peps->dwDirectionAssigned = USB_IN_TRANSFER;
			WriteIndexedReg(pContext, dwEndpoint, ECR, 0x0000);
		}

		// Clear all Status bits and leave the Endpoint interrupt disabled
		// Clear Fifos, and all register bits
		ResetEndpoint(pContext,peps);

		// Set Transfer Type
		BYTE bTransferType = pEndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
		DEBUGCHK(bTransferType != USB_ENDPOINT_TYPE_CONTROL);
		switch(bTransferType)
		{
		case USB_ENDPOINT_TYPE_ISOCHRONOUS:
			// Set the ISO bit
			SetClearIndexedReg(pContext, dwEndpoint,ECR,
			                   IME, SET);
			break;

		case USB_ENDPOINT_TYPE_BULK:
		case USB_ENDPOINT_TYPE_INTERRUPT:
		default:
			// Clear ISO bit - Set type to Bulk
			SetClearIndexedReg(pContext, dwEndpoint,ECR,
			                   IME, CLEAR);
		}

		peps->dwEndpointType = bTransferType;
		peps->dwPacketSizeAssigned = wMaxPacketSize;

		// Set the Max Packet Register
		WriteIndexedReg(pContext, dwEndpoint, MPR, wMaxPacketSize);

		UfnPdd_ClearEndpointStall(pvPddContext,dwEndpoint);

		// Clear outstanding interrupts
		ClearEndpointInterrupt(pContext, dwEndpoint);

	}

	peps->fInitialized = TRUE;
	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}


// Deinitialize an endpoint.
DWORD
WINAPI
UfnPdd_DeinitEndpoint(
    PVOID pvPddContext,
    DWORD dwEndpoint
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	DEBUGCHK(EP_VALID(dwEndpoint));

	RETAILMSG(DBG, (_T("%s  UfnPdd_DeinitEndpoint\r\n"),
	                pszFname));

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);
	LOCK_ENDPOINT(peps);

	DEBUGCHK(peps->fInitialized);
	DEBUGCHK(peps->pTransfer == NULL);

	// Reset and disable the endpoint
	// Mask endpoint interrupts
	ResetEndpoint(pContext, peps);

	// Clear endpoint interrupts
	ClearEndpointInterrupt(pContext, dwEndpoint);


	peps->fInitialized = FALSE;
	UNLOCK_ENDPOINT(peps);


	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}

DWORD
WINAPI
UfnPdd_StallEndpoint(
    PVOID pvPddContext,
    DWORD dwEndpoint
)
{
	DWORD dwRet = ERROR_SUCCESS;
	//WORD bEP0CR, bECR;
	SETFNAME();
	FUNCTION_ENTER_MSG();

	DEBUGCHK(EP_VALID(dwEndpoint));


	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	if(dwEndpoint == 0)
		RETAILMSG(1, (_T("%s  UfnPdd_StallEndpoint, EP : %d, \r\n"), pszFname,dwEndpoint));


	PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);
	DEBUGCHK(peps->fInitialized);
	LOCK_ENDPOINT(peps);

	if (dwEndpoint == 0)
	{
		// Must Clear Out Packet Ready when sending Stall
		DEBUGMSG(ZONE_SEND, (_T("%s Writing 0x%02x to EP0_CSR_REG\r\n"), pszFname,
		                     bEp0StallBits));

		StallFlag = TRUE;

		SetClearIndexedReg(pContext, dwEndpoint, EP0CR, EP0ESS, SET);

		// Set Flag so that SendControlStatusHandshked does not
		// duplicate this HW Write. Manual says all bits need
		// to be set at the same time.
		pContext->sendDataEnd = FALSE;
		pContext->Ep0State = EP0_STATE_IDLE;
	}
	else
	{
		// Must Clear Out Packet Ready when sending Stall

		SetClearIndexedReg(pContext, dwEndpoint, ECR, ESS, SET);

	}

	UNLOCK_ENDPOINT(peps);
	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}


// Send the control status handshake.
DWORD
WINAPI
UfnPdd_SendControlStatusHandshake(
    PVOID           pvPddContext,
    DWORD           dwEndpoint
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	RETAILMSG(DBG, (_T("%s  UfnPdd_SendControlStatusHandshake\r\n"),
	                pszFname));

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	DEBUGCHK(dwEndpoint == 0);

	// This function is only valid for Endpoint 0
	EP_STATUS *peps = GetEpStatus(pContext, 0);
	DEBUGCHK(peps->fInitialized);

	// Remove the Out Packet Ready Condition
	if(pContext->sendDataEnd)
	{
		LOCK_ENDPOINT(peps);

		DEBUGMSG(ZONE_SEND, (_T("%s Sending 0 packet \r\n"), pszFname));

		pContext->sendDataEnd = FALSE;

		UNLOCK_ENDPOINT(peps);
	}

	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}


// Set the address of the device on the USB.
DWORD
WINAPI
UfnPdd_SetAddress(
    PVOID pvPddContext,
    BYTE  bAddress
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	RETAILMSG(DBG, (_T("%s  UfnPdd_SetAddress\r\n"),
	                pszFname));

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);


	WriteReg(pContext, FARR, bAddress);

	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}


// Is endpoint Stalled?
DWORD
WINAPI
UfnPdd_IsEndpointHalted(
    PVOID pvPddContext,
    DWORD dwEndpoint,
    PBOOL pfHalted
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	DWORD dwRet = ERROR_SUCCESS;
	WORD bRegVal;
	BOOL fHalted = FALSE;

	RETAILMSG(1, (_T("%s  UfnPdd_IsEndpointHalted: %d\r\n"),
	              pszFname,dwEndpoint));

	DEBUGCHK(EP_VALID(dwEndpoint));
	PREFAST_DEBUGCHK(pfHalted);

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);
	LOCK_ENDPOINT(peps);

	// Check the Appropriate Stall Bit
	if (dwEndpoint == 0)
	{
		// Must Clear Out Packet Ready when sending Stall
		bRegVal = ReadReg(pContext, EP0CR);
		if (bRegVal & EP0ESS)
			fHalted = TRUE;
	}
	else
	{
		bRegVal = ReadIndexedReg(pContext,dwEndpoint, ECR);
		if (bRegVal & ESS)
			fHalted = TRUE;
	}

	*pfHalted = fHalted;
	pContext->sendDataEnd  = FALSE;
	UNLOCK_ENDPOINT(peps);

	FUNCTION_LEAVE_MSG();

	return dwRet;
}


DWORD
WINAPI
UfnPdd_InitiateRemoteWakeup(
    PVOID pvPddContext
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	RETAILMSG(DBG, (_T("%s  UfnPdd_InitiateRemoteWakeup\r\n"),
	                pszFname));

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	SetClearReg(pContext, SCR, (RRDE | MFRM), SET);

	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}


DWORD
WINAPI
UfnPdd_RegisterDevice(
    PVOID                           pvPddContext,
    PCUSB_DEVICE_DESCRIPTOR         pHighSpeedDeviceDesc,
    PCUFN_CONFIGURATION             pHighSpeedConfig,
    PCUSB_CONFIGURATION_DESCRIPTOR  pHighSpeedConfigDesc,
    PCUSB_DEVICE_DESCRIPTOR         pFullSpeedDeviceDesc,
    PCUFN_CONFIGURATION             pFullSpeedConfig,
    PCUSB_CONFIGURATION_DESCRIPTOR  pFullSpeedConfigDesc,
    PCUFN_STRING_SET                pStringSets,
    DWORD                           cStringSets
)
{
	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	// Nothing to do.

	return ERROR_SUCCESS;
}


DWORD
WINAPI
UfnPdd_DeregisterDevice(
    PVOID   pvPddContext
)
{
	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	return ERROR_SUCCESS;
}


VOID
WINAPI
UfnPdd_PowerDown(
    PVOID pvPddContext
)
{
	SETFNAME();
	DEBUGMSG(ZONE_POWER, (_T("%s\r\n"), pszFname));

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	// Nothing to do.
}


VOID
WINAPI
UfnPdd_PowerUp(
    PVOID pvPddContext
)
{
	SETFNAME();
	DEBUGMSG(ZONE_POWER, (_T("%s\r\n"), pszFname));

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	ValidateContext(pContext);

	// Nothing to do.
}


DWORD
WINAPI
UfnPdd_IOControl(
    PVOID           pvPddContext,
    IOCTL_SOURCE    source,
    DWORD           dwCode,
    PBYTE           pbIn,
    DWORD           cbIn,
    PBYTE           pbOut,
    DWORD           cbOut,
    PDWORD          pcbActualOut
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	FUNCTION_LEAVE_MSG();

	return TRUE;
}



// Initialize the device.
DWORD
WINAPI
UfnPdd_Init(
    LPCTSTR                     pszActiveKey,
    PVOID                       pvMddContext,
    PUFN_MDD_INTERFACE_INFO     pMddInterfaceInfo,
    PUFN_PDD_INTERFACE_INFO     pPddInterfaceInfo
)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	static const UFN_PDD_INTERFACE_INFO sc_PddInterfaceInfo =
	    {
	        UFN_PDD_INTERFACE_VERSION,
	        (UFN_PDD_CAPS_SUPPORTS_FULL_SPEED | UFN_PDD_CAPS_SUPPORTS_HIGH_SPEED),
	        ENDPOINT_COUNT,
	        NULL, // This gets filled in later

	        &UfnPdd_Deinit,
	        &UfnPdd_IsConfigurationSupportable,
	        &UfnPdd_IsEndpointSupportable,
	        &UfnPdd_InitEndpoint,
	        &UfnPdd_RegisterDevice,
	        &UfnPdd_DeregisterDevice,
	        &UfnPdd_Start,
	        &UfnPdd_Stop,
	        &UfnPdd_IssueTransfer,
	        &UfnPdd_AbortTransfer,
	        &UfnPdd_DeinitEndpoint,
	        &UfnPdd_StallEndpoint,
	        &UfnPdd_ClearEndpointStall,
	        &UfnPdd_SendControlStatusHandshake,
	        &UfnPdd_SetAddress,
	        &UfnPdd_IsEndpointHalted,
	        &UfnPdd_InitiateRemoteWakeup,
	        &UfnPdd_PowerDown,
	        &UfnPdd_PowerUp,
	        &UfnPdd_IOControl,
	    };

	PCTRLR_PDD_CONTEXT pContext = NULL;
	RETAILMSG(DBG, (_T(" USB Function Driver Init \r\n")));


	pContext = &g_pdd;
	memset(pContext, 0, sizeof(g_pdd));

	pContext->dwSig = SC2443_SIG;

	pContext->pvMddContext = pvMddContext;

	pContext->pfnNotify = pMddInterfaceInfo->pfnNotify;


	for (DWORD dwEp = 0; dwEp < dim(pContext->rgEpStatus); ++dwEp)
	{
		pContext->rgEpStatus[dwEp].dwEndpointNumber = dwEp;
	}


	pContext->attachedState = UFN_DETACH;
	MapRegisterSet(pContext);


	ResetDevice(pContext);

	memcpy(pPddInterfaceInfo, &sc_PddInterfaceInfo, sizeof(sc_PddInterfaceInfo));
	pPddInterfaceInfo->pvPddContext = pContext;

	//HookInterrupt(IRQ_USBD,(FARPROC)InterruptThread);
	
	//IPLIntrEnableIrq(IRQ_USBD);
	UINT32 mask;
	S3C2443_INTR_REG*g_pIntrRegs = (S3C2443_INTR_REG*)OALPAtoVA(
       	S3C2443_BASE_REG_PA_INTR, FALSE);
	//IPLIntrDoneIrq(IRQ_USBD);
	mask = 1 << IRQ_USBD;
	OUTREG32(&g_pIntrRegs->SRCPND, mask);
	CLRREG32(&g_pIntrRegs->INTMSK, mask);
	return ERROR_SUCCESS ;
}
	